/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ua.yandex.collections;

/**
 *
 * @author Neophron
 */
public class MyLinkedList implements MyList {

    private static class Node {

        private Object element;
        private Node next;

        public Node(Object e) {
            this(e, null);
        }

        public Node(Object e, Node n) {
            element = e;
            next = n;
        }
    }

    private Node first;
    private int size;

    public MyLinkedList() {
        first = null;
        size = 0;
    }

    public void addFirst(Object e) {
        add(0, e);
    }

    public void addLast(Object e) {
        add(e);
    }

    public Object getFirst() {
        return get(0);
    }

    public Object getLast() {
        return get(size - 1);
    }

    public Object removeFirst() {
        return remove(0);
    }

    public Object removeLast() {
        return remove(size - 1);
    }

    private void checkIndex(int index) {
        if (index > size) {
            throw new IllegalArgumentException();
        }
    }

    private void checkIndexForGet(int index) {
        if (index >= size) {
            throw new IllegalArgumentException();
        }
    }

    @Override
    public void add(Object e) {
        add(size, e);
    }

    @Override
    public void add(int index, Object e) {
        if (e == null) {
            return;
        }
        addAll(index, new Object[]{e});
    }

    @Override
    public void addAll(Object[] c) {
        addAll(size, c);
    }

    @Override
    public void addAll(int index, Object[] c) {
        if (c == null) {
            return;
        }
        checkIndex(index);
        if (first == null) {
            Node tmp = null;
            if (c.length > 0) {
                first = new Node(c[0]);
                tmp = first;
                size++;
            }
            for (int i = 1; i < c.length; i++) {
                tmp.next = new Node(c[i]);
                tmp = tmp.next;
                size++;
            }
            return;
        }
        Node tmp = first;
        for (int i = 0; i < index - 1; i++) {
            tmp = tmp.next;
        }
        Node tmpNext = tmp.next;
        for (int i = 0; i < c.length; i++) {
            tmp.next = new Node(c[i]);
            tmp = tmp.next;
            size++;
        }
        tmp.next = tmpNext;
    }

    @Override
    public Object get(int index) {
        checkIndexForGet(index);
        Node tmp = first;
        for (int i = 0; i < index; i++) {
            tmp = tmp.next;
        }
        return tmp.element;
    }

    @Override
    public Object remove(int index) {
        checkIndexForGet(index);
        Node tmp = first;
        for (int i = 0; i < index - 1; i++) {
            tmp = tmp.next;
        }
        Object res = tmp.next.element;
        tmp.next = tmp.next.next;
        size--;
        return res;
    }

    @Override
    public void set(int index, Object e) {
        checkIndexForGet(index);
        Node tmp = first;
        for (int i = 0; i < index; i++) {
            tmp = tmp.next;
        }
        tmp.element = e;
    }

    @Override
    public int indexOf(Object o) {
        Node tmp = first;
        for (int i = 0; i < size; i++) {
            if (tmp.element.equals(o)) {
                return i;
            }
            tmp = tmp.next;
        }
        return -1;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public void clear() {
        first = null;
        size = 0;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public Object[] toArray() {
        Object[] res = new Object[size];
        Node tmp = first;
        for (int i = 0; i < size; i++) {
            res[i] = tmp.element;
            tmp = tmp.next;
        }
        return res;
    }

    @Override
    public String toString() {
        StringBuilder str = new StringBuilder();
        Node tmp = first;
        if (tmp != null) {
            str.append(tmp.element.toString());
            tmp = tmp.next;
        }
        for (int i = 1; i < size; i++) {
            str.append(", " + tmp.element.toString());
            tmp = tmp.next;
        }
        return str.toString();
    }

}
